package com.mlx.meng.verify;

import com.mlx.meng.tool.DataPermissionException;
import com.mlx.meng.tool.DataPermissionUtil;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

public class DataPermissionRowVerification {

    private HashMap<String, HashMap<String, HashSet<String>>> rowElementMap;

    public DataPermissionRowVerification(){
        this.rowElementMap = new HashMap<>();
    }

    private HashMap<String, HashSet<String>> get(String tableName){
        HashMap<String, HashSet<String>> tablePermission = rowElementMap.get(tableName);
        if (DataPermissionUtil.isEmpty(tablePermission)){
            return new HashMap<>();
        }
        return tablePermission;
    }

    private HashMap<String, HashSet<String>> get(String[] foreignKeys){
        HashMap<String, HashSet<String>> fieldMap =new HashMap<>();
        int length = foreignKeys.length;
        if (length > 0){
            for (int i = 0 ; i < length ; i++){
                String foreignKey = foreignKeys[i];
                if (!(DataPermissionUtil.checkForeignKeyFormat(foreignKey))){
                    throw new DataPermissionException(String.format("foreignKeys外键数组第【%d】个元素发不是合法的外键映射表达式", i + 1));
                }
                String[] split = foreignKey.split(":");
                Map<String, HashSet<String>> tablePermissions = get(split[1]);
                if (tablePermissions.isEmpty()){
                    continue;
                }
                if (!(tablePermissions.containsKey(split[2]))){
                    continue;
                }
                HashSet<String> collection = tablePermissions.get(split[2]);
                fieldMap.put(split[0], collection);
            }
        }
        return fieldMap;
    }

    public void put(String tableName, String fieldName, String permissions){
        if (rowElementMap.containsKey(tableName)){

            Map<String, HashSet<String>> fieldMap = rowElementMap.get(tableName);

            if (fieldMap.containsKey(fieldName)){
                Collection<String> collection = fieldMap.get(fieldName);
                collection.add(permissions);
            }else {
                HashSet<String> collection = new HashSet<>();
                collection.add(permissions);
                fieldMap.put(fieldName, collection);
            }

        }else {

            HashMap<String, HashSet<String>> fieldMap = new HashMap<>();
            HashSet<String> collection = new HashSet<>();
            collection.add(permissions);
            fieldMap.put(fieldName, collection);
            rowElementMap.put(tableName, fieldMap);
        }
    }

    public DataPermissionRowEntityVerification buildEntityDataPermissionRow(String tableName, String[] foreignKeys){
        return new DataPermissionRowEntityVerification(tableName, foreignKeys);
    }

    public class DataPermissionRowEntityVerification {

        private HashMap<String, HashSet<String>> entityRowPermission;

        private Set<String> permissionField;

        private DataPermissionRowEntityVerification(String tableName, String[] foreignKeys){

            HashMap<String, HashSet<String>> map = new HashMap<>();
            HashMap<String, HashSet<String>> tablePermission = get(tableName);
            HashMap<String, HashSet<String>> foreignKeysPermission = get(foreignKeys);

            Set<String> foreignKeysKeySet = foreignKeysPermission.keySet();
            Set<String> permissionFieldError = new HashSet<>();
            for (String k : foreignKeysKeySet){
                if (tablePermission.containsKey(k)){
                    permissionFieldError.add(k);
                }
            }
            if (DataPermissionUtil.isNotEmpty(permissionFieldError)){
                throw new DataPermissionException(String.format("权限字段重复：但是外键映射指定外键字段【%s】中，但是表权限字段已经包含它们", permissionFieldError.toString()));
            }
            map.putAll(tablePermission);
            map.putAll(foreignKeysPermission);
            this.permissionField = map.keySet();
            this.entityRowPermission = map;
        }

        public Set<String> getPermissionField() {
            return permissionField;
        }

        public boolean isNotDataPermission(Object data, Map<String, Field> classFieldMap){
            if (DataPermissionUtil.isEmpty(data)){
                return false;
            }
            boolean have = false;

            for (String k : permissionField){

                Object fieldValue = null;

                try {
                    fieldValue = classFieldMap.get(k).get(data);
                } catch (IllegalAccessException e) {
                    throw new DataPermissionException("数据权限异常：判断是否有数据权限时，获取数据的【%s】属性时，无【%s】属性的访问权限；", k, k);
                } catch (Exception e) {
                    throw new DataPermissionException("数据权限异常：判断是否有数据权限时，获取数据的【%s】属性时，发生了异常，异常信息：%s", k, e.getMessage());
                }

                if (DataPermissionUtil.isNotEmpty(fieldValue)){

                    if (entityRowPermission.get(k).contains(fieldValue.toString())){
                        have = true;
                        break;
                    }
                }
            }

            return !have;
        }

        public boolean isNotDataPermission(Object data, Method getMethod){
            if (DataPermissionUtil.isEmpty(data)){
                return false;
            }
            boolean have = false;
            for (String k : permissionField){

                Object fieldValue = null;
                try {
                    fieldValue = getMethod.invoke(data, k);
                } catch (IllegalAccessException e) {
                    throw new DataPermissionException("数据权限异常：判断是否有数据权限时，执行【%s】属性get方法时没有方法的访问权限；", k);
                } catch (InvocationTargetException e) {
                    throw new DataPermissionException("数据权限异常：判断是否有数据权限时，执行【%s】属性get方法时发生执行异常；", k);
                }catch (Exception e){
                    throw new DataPermissionException("数据权限异常：判断是否有数据权限时，执行【%s】属性get方法时发生未知异常；", k);
                }
                if (DataPermissionUtil.isNotEmpty(fieldValue)){
                    if (entityRowPermission.get(k).contains(fieldValue.toString())){
                        have = true;
                        break;
                    }
                }
            }
            return !have;
        }

        public boolean isNotExistDataPermission(){
            return DataPermissionUtil.isEmpty(entityRowPermission);
        }
    }
}
